using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ComponentModel;
using PlanetWPF.Toolbelt.Properties;


namespace PlanetWPF.Toolbelt.Controls
{

    /// <summary>
    /// A control that provides a tabular view of a collection of objects.
    /// </summary>
    [TemplatePart(Name = "PART_Grid", Type = typeof(PowerGridView))]
    [TemplatePart(Name = "PART_Header", Type = typeof(PowerGridColumnHeaderRow))]
    public class PowerGrid : Control, IPowerGrid
    {

        #region Dependency Properties

        /// <summary>
        /// A <see cref="DependencyProperty"/> to hold the 
        /// <see cref="PowerGridColumnCollection"/> assigned to this grid.
        /// <seealso cref="Columns"/>
        /// </summary>
        public static readonly DependencyProperty ColumnsProperty;
        /// <summary>
        /// A <see cref="DependencyProperty"/> to hold the collection of objects
        /// displayed by this grid.
        /// <seealso cref="Items"/>
        /// </summary>
        public static readonly DependencyProperty ItemsProperty;
        /// <summary>
        /// A <see cref="DependencyProperty"/> to hold the collection of 
        /// <see cref="PowerGridRow"/>s with selected cells.
        /// <seealso cref="SelectedRows"/>
        /// </summary>
        public static readonly DependencyProperty SelectedRowsProperty;
        /// <summary>
        /// A <see cref="DependencyPropertyKey"/> used to reference the 
        /// read only <see cref="DependencyProperty"/> holding the currently
        /// focused <see cref="PowerGridCell"/>
        /// <seealso cref="Current"/>
        /// </summary>
        private static readonly DependencyPropertyKey CurrentPropertyKey;
        /// <summary>
        /// A <see cref="DependencyProperty"/> to hold the DataTemplate for
        /// all <see cref="PowerGridCell"/>s associated with this PowerGrid
        /// </summary>
        public static readonly DependencyProperty CellDataTemplateProperty;

        #endregion

        /// <summary>
        /// A serialized list of objects created during a copy and paste operation.
        /// <seealso cref="ExecuteCopySelectedCells"/>
        /// </summary>
        private List<object> _CopyStore = new List<object>();
        /// <summary>
        /// State marker to indicate that the next 
        /// <see cref="PowerGridCell.CellSelectedEvent">CellSelectedEvent</see> 
        /// should cause <see cref="Current"/> to change.
        /// </summary>
        private Boolean _CurrentChanging = false;

        /// <summary>
        /// A collection of <see cref="PowerGridCell"/>s that are currently
        /// selected.
        /// </summary>
        private List<PowerGridCell> m_SelectedCells = new List<PowerGridCell>();

        private PowerGridView m_GridView;
        private PowerGridColumnHeaderRow m_Header;

        protected List<object> CopyStore
        {
            get { return _CopyStore; }
            set { _CopyStore = value; }
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public PowerGrid()
        {
            //Initialize the Columns property because WPF no longer does this automatically.
            Columns = new PowerGridColumnCollection();
            SelectedRows = new List<PowerGridRow>();
            SelectedCells = new List<PowerGridCell>();
            Loaded += new RoutedEventHandler(OnLoad);
        }

        private void OnLoad(object sender, RoutedEventArgs e)
        {
            m_GridView = Template.FindName(PlanetWPF.Toolbelt.Properties.Resources.Part_Grid, this)as PowerGridView;
            if (m_GridView == null)
            {
                throw new NotSupportedException(PlanetWPF.Toolbelt.Properties.Resources.PowerGrid_InvalidGridView);
            }
            m_Header = Template.FindName(PlanetWPF.Toolbelt.Properties.Resources.Part_Header, this) as PowerGridColumnHeaderRow;
            if (m_Header == null)
            {
                throw new NotSupportedException(PlanetWPF.Toolbelt.Properties.Resources.PowerGrid_InvalidHeader);
            }
        }

        /// <summary>
        /// Static constructor. Responsible for initializing dependency properties, overriding
        /// the Default Style, and registering Class Event Handlers and CommandBindings.
        /// </summary>
        static PowerGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(PowerGrid),
                new FrameworkPropertyMetadata(typeof(PowerGrid)));

            ColumnsProperty = DependencyProperty.Register(
                "Columns",
                typeof(PowerGridColumnCollection),
                typeof(PowerGrid));

            ItemsProperty = DependencyProperty.Register(
                "Items",
                typeof(IList),
                typeof(PowerGrid),
                new FrameworkPropertyMetadata(null, ItemsChanged));

            SelectedRowsProperty = DependencyProperty.Register(
                "SelectedRows",
                typeof(List<PowerGridRow>),
                typeof(PowerGrid),
                new FrameworkPropertyMetadata(null));

            CurrentPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
              "Current",
              typeof(PowerGridCell),
              typeof(PowerGrid),
              new UIPropertyMetadata(null, CoreCurrentCellChanged));

            CellDataTemplateProperty = DependencyProperty.Register(
              "CellDataTemplate",
              typeof(DataTemplate),
              typeof(PowerGrid),
              new UIPropertyMetadata(null));

            //Bind the Copy command to the grid.
            CommandManager.RegisterClassCommandBinding(
              typeof(PowerGrid),
              new CommandBinding(ApplicationCommands.Copy, ExecuteCopySelectedCells, CanExecuteCopySelectedCells));

            CommandManager.RegisterClassCommandBinding(
                typeof(PowerGrid),
                new CommandBinding(ApplicationCommands.Paste, ExecutePasteCopiedCells, CanExecutePasteCopiedCells));

            EventManager.RegisterClassHandler(
              typeof(PowerGrid),
              PowerGridCell.PreviewCellSelectedEvent,
              new RoutedEventHandler(CoreCellSelected));

            EventManager.RegisterClassHandler(
              typeof(PowerGrid),
              PowerGridCell.PreviewCellDeselectedEvent,
              new RoutedEventHandler(CoreCellDeselected));

        }



        /// <summary>
        /// Holds a list of currently selected <see cref="PowerGridCell"/>s within
        /// this PowerGrid.
        /// </summary>
        public List<PowerGridCell> SelectedCells
        {
            get { return m_SelectedCells; }
            set { m_SelectedCells = value; }
        }


        internal void AddSelectedCell(PowerGridCell selected)
        {
            if (!SelectedCells.Contains(selected))
            {
                SelectedCells.Add(selected);
                AddSelectedRow(selected.ParentRow);
            }
        }


        public DataTemplate CellDataTemplate
        {
            get { return (DataTemplate)GetValue(CellDataTemplateProperty); }
            set { SetValue(CellDataTemplateProperty, value); }
        }

        public PowerGridCell Current
        {
            get { return (PowerGridCell)GetValue(CurrentPropertyKey.DependencyProperty); }
            private set { SetValue(CurrentPropertyKey, value); }
        }

        internal void SelectRange(PowerGridCell endCell)
        {

        }

        internal void SelectRange(PowerGridCell startCell, PowerGridCell endCell)
        {

        }

        internal void RemoveSelectedCell(PowerGridCell unSelected)
        {
            if (SelectedCells.Contains(unSelected))
            {
                SelectedCells.Remove(unSelected);
            }
            if (SelectedRows.Contains(unSelected.ParentRow) && unSelected.ParentRow.SelectedCells.Count == 0)
            {
                RemoveSelectedRow(unSelected.ParentRow);
            }
        }

        internal void ClearSelectedCells()
        {
            PowerGridCell[] tmpArray = new PowerGridCell[SelectedCells.Count];
            SelectedCells.CopyTo(tmpArray);
            foreach (PowerGridCell cell in tmpArray)
            {
                cell.Selected = false;
            }
            //SelectedCells.Clear();
        }
        /// <summary>
        /// Holds the collection of <see cref="PowerGridColumn"/>s for the PowerGrid
        /// </summary>
        public PowerGridColumnCollection Columns
        {
            get { return (PowerGridColumnCollection)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        public IList Items
        {
            get { return (IList)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }

        private static void ItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //TODO:Implement this handler
        }

        private static void CoreCurrentCellChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        private static void ExecuteCopySelectedCells(object sender, ExecutedRoutedEventArgs e)
        {
            PowerGrid tmpGrid = sender as PowerGrid;
            if (tmpGrid != null)
            {
                foreach (PowerGridRow row in tmpGrid.SelectedRows)
                {
                    tmpGrid.CopyStore.Add(row.CopyOutSelected());
                }
            }
        }

        private static void CanExecuteCopySelectedCells(object sender, CanExecuteRoutedEventArgs e)
        {
            PowerGrid tmpgrid = sender as PowerGrid;
            if (tmpgrid != null)
            {
                if (tmpgrid.SelectedRows == null)
                {
                    tmpgrid.SelectedRows = new List<PowerGridRow>();
                }
                if (tmpgrid.SelectedRows.Count != 0)
                {
                    e.CanExecute = true;
                }
                else
                {
                    e.CanExecute = false;
                }
            }
        }

        private static void ExecutePasteCopiedCells(object sender, ExecutedRoutedEventArgs e)
        {
            PowerGrid tmpGrid = sender as PowerGrid;
            if (tmpGrid != null)
            {
                ItemsControl ic = tmpGrid.m_GridView.Template.FindName(PlanetWPF.Toolbelt.Properties.Resources.Part_ItemsControl, tmpGrid.m_GridView) as ItemsControl;
                CollectionView cv = ic.Items;
                tmpGrid.ClearSelectedCells();
                cv.SortDescriptions.Clear();
                foreach (object tmpCells in tmpGrid._CopyStore)
                {
                    tmpGrid.Items.Add(tmpCells);
                }
                cv.Refresh();
                tmpGrid.CopyStore.Clear();
            }
        }

        private static void CanExecutePasteCopiedCells(object sender, CanExecuteRoutedEventArgs e)
        {
            PowerGrid tmpGrid = sender as PowerGrid;
            if (tmpGrid != null)
            {
                e.CanExecute = tmpGrid._CopyStore.Count > 0;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        public List<PowerGridRow> SelectedRows
        {
            get { return (List<PowerGridRow>)GetValue(SelectedRowsProperty); }
            set { SetValue(SelectedRowsProperty, value); }
        }

        internal void AddSelectedRow(PowerGridRow pRow)
        {
            if (SelectedRows == null)
            {
                SelectedRows = new List<PowerGridRow>();
            }

            if (!SelectedRows.Contains(pRow))
            {
                SelectedRows.Add(pRow);
            }
        }
        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            _CurrentChanging = true;
            base.OnPreviewMouseLeftButtonDown(e);
        }

        internal void RemoveSelectedRow(PowerGridRow pRow)
        {
            if (SelectedRows == null)
            {
                SelectedRows = new List<PowerGridRow>();
            }
            if (SelectedRows.Contains(pRow))
            {
                SelectedRows.Remove(pRow);
            }
        }

        private static void CoreCellSelected(Object sender, RoutedEventArgs e)
        {
            PowerGrid tmpgrid = sender as PowerGrid;
            tmpgrid.OnCellSelected(sender, e);
        }

        protected virtual void OnCellSelected(Object sender, RoutedEventArgs e)
        {
            PowerGridCell tmpCell = e.OriginalSource as PowerGridCell;
            if (tmpCell != null)
            {
                if (_CurrentChanging)
                {
                    _CurrentChanging = false;
                    Current = tmpCell;
                }
                AddSelectedCell(tmpCell);
            }
        }

        private static void CoreCellDeselected(Object sender, RoutedEventArgs e)
        {
            PowerGrid tmpgrid = sender as PowerGrid;
            tmpgrid.OnCellDeselected(sender, e);
        }

        protected virtual void OnCellDeselected(Object sender, RoutedEventArgs e)
        {
            PowerGridCell tmpCell = e.OriginalSource as PowerGridCell;
            if (tmpCell != null)
            {
                RemoveSelectedCell(tmpCell);
            }
        }
    }
}



